SnippetIntent PRO
需要 Scripting PRO
SnippetIntent 是一种特殊类型的 AppIntent,可在 Shortcuts 中生成原生的 Snippet UI 卡片。它适用于:
- 多步骤表单式交互
- 从 Shortcuts 中获取用户输入
- 键值选择、确认、展示结果等轻量级交互
- 在 Shortcuts 工作流中内嵌 UI 组件
SnippetIntent 特点如下:
- 在 Scripting 中必须通过
AppIntentManager.register 注册
protocol 必须为 AppIntentProtocol.SnippetIntent
perform() 必须返回一个 VirtualNode(TSX UI)
- 在脚本中必须以
Intent.snippetIntent() 封装后返回
- Shortcuts 必须使用「Show Snippet Intent」动作才能显示 Snippet UI
系统要求
SnippetIntent 只能在 iOS 26 及以上系统运行。
在 iOS 26 以下环境:
- 无法调用
Intent.snippetIntent
- 无法使用
Intent.requestConfirmation
- Shortcuts 中不存在「Show Snippet Intent」动作
- SnippetIntent 类型的 AppIntent 不会被 Shortcuts 正常识别
注册 SnippetIntent(app_intents.tsx)
在 app_intents.tsx 中声明 SnippetIntent:
1export const PickColorIntent = AppIntentManager.register<void>({
2 name: "PickColorIntent",
3 protocol: AppIntentProtocol.SnippetIntent,
4 perform: async () => {
5 return <PickColorView />
6 }
7})
再例如:
1export const ShowResultIntent = AppIntentManager.register({
2 name: "ShowResultIntent",
3 protocol: AppIntentProtocol.SnippetIntent,
4 perform: async ({ content }: { content: string }) => {
5 return <ResultView content={content} />
6 }
7})
要求:
protocol 必须为 AppIntentProtocol.SnippetIntent
perform() 必须返回 VirtualNode
- 与普通 AppIntent 区别在于返回的是 UI,而非数据
SnippetIntent 返回值封装:Intent.snippetIntent
SnippetIntent 不能直接作为 JS 返回值,必须通过 Intent.snippetIntent() 包装成 IntentSnippetIntentValue。
1const snippetValue = Intent.snippetIntent({
2 value: Intent.text("Some value returning for Shortcuts"),
3 snippetIntent: ShowResultIntent({
4 content: "Example Text"
5 })
6})
7
8Script.exit(snippetValue)
类型定义
1type SnippetIntentValue = {
2 value?: IntentAttributedTextValue | IntentFileURLValue | IntentJsonValue | IntentTextValue | IntentURLValue | IntentFileValue | null
3 snippetIntent: AppIntent<any, VirtualNode, AppIntentProtocol.SnippetIntent>
4}
5
6declare class IntentSnippetIntentValue extends IntentValue<
7 'SnippetIntent',
8 SnippetIntentValue
9> {
10 value: SnippetIntentValue
11 type: 'SnippetIntent'
12}
封装的返回值可被 Shortcuts 的「Show Snippet Intent」动作识别并展示 UI。
Snippet 确认界面:Intent.requestConfirmation
SnippetIntent 支持在执行逻辑中先请求用户确认某个操作。此能力同样基于 iOS 26。
1Intent.requestConfirmation(
2 actionName: ConfirmationActionName,
3 intent: AppIntent<any, VirtualNode, AppIntentProtocol.SnippetIntent>,
4 options?: {
5 dialog?: Dialog;
6 showDialogAsPrompt?: boolean;
7 }
8): Promise<void>
ConfirmationActionName
这些名称会影响 Shortcuts UI 中呈现的文案,例如 “Set …”、“Add …”、“Toggle …” 等。
示例值:
"add" | "addData" | "book" | "buy" | "call" | "checkIn" |
"continue" | "create" | "do" | "download" | "filter" |
"find" | "get" | "go" | "log" | "open" | "order" |
"pay" | "play" | "playSound" | "post" | "request" |
"run" | "search" | "send" | "set" | "share" |
"start" | "startNavigation" | "toggle" | "turnOff" |
"turnOn" | "view"
示例
1await Intent.requestConfirmation(
2 "set",
3 PickColorIntent()
4)
效果:
- Shortcuts 弹出 PickColorIntent 对应的 Snippet UI
- 用户点击确认后 Promise resolve
- 用户取消时脚本执行终止
Shortcuts 的「Show Snippet Intent」动作(iOS 26+)
Shortcuts 在 iOS 26 新增动作:
Show Snippet Intent
用于展示 SnippetIntent 返回的 Snippet UI。
与其他动作对比
| Shortcuts 动作 |
显示界面 |
支持 SnippetIntent |
场景 |
| Run Script |
无 UI |
否 |
纯数据处理 |
| Run Script in App |
Scripting App UI(前台) |
否 |
大型 UI、文件选择等 |
| Show Snippet Intent(iOS 26+) |
Snippet 卡片 UI |
是 |
SnippetIntent 场景 |
使用方式:
- 在 Shortcuts 中添加「Show Snippet Intent」
- 选择脚本项目(需包含 intent.tsx)
- 脚本返回
Intent.snippetIntent(...)
- Shortcuts 显示 Snippet UI
IntentMemoryStorage — 跨 AppIntent 状态共享
1. 为什么需要 IntentMemoryStorage
由于系统行为,每次 Intent 执行后:
- AppIntent 的
perform() 执行完毕后立即销毁上下文
intent.tsx 执行完并调用 Script.exit() 后脚本上下文也会完全释放
因此无法依赖 JS 变量在多个 Intent 之间保持状态。
例如:
- PickColorIntent(选择颜色)
- SetColorIntent(设置颜色)
- ShowResultIntent(展示颜色结果)
在这些 Intent 之间共享状态必须依赖持久化存储。
2. IntentMemoryStorage 提供轻量级、跨 Intent 的共享存储
API 定义:
1namespace IntentMemoryStorage {
2 function get<T>(key: string): T | null
3 function set(key: string, value: any): void
4 function remove(key: string): void
5 function contains(key: string): boolean
6 function clear(): void
7 function keys(): string[]
8}
用途:
- 存储小量状态,例如当前颜色、当前步骤、临时选项
- 在多个 AppIntent 之间共享数据
- 生命周期跨 Intent 调用,但随脚本生命周期管理
示例:存储用户颜色选择
1IntentMemoryStorage.set("color", "systemBlue")
2
3const color = IntentMemoryStorage.get<Color>("color")
建议
-
不要存储大型数据(如大图像、长文本)
-
大型数据请使用:
Storage(持久键值存储)
FileManager 写入 appGroupDocumentsDirectory
IntentMemoryStorage 适合作为临时状态共享,不适合当作数据库使用。
完整示例(iOS 26+)
app_intents.tsx
1export const SetColorIntent = AppIntentManager.register({
2 name: "SetColorIntent",
3 protocol: AppIntentProtocol.AppIntent,
4 perform: async (color: Color) => {
5 IntentMemoryStorage.set("color", color)
6 }
7})
8
9export const PickColorIntent = AppIntentManager.register<void>({
10 name: "PickColorIntent",
11 protocol: AppIntentProtocol.SnippetIntent,
12 perform: async () => {
13 return <PickColorView />
14 }
15})
16
17export const ShowResultIntent = AppIntentManager.register({
18 name: "ShowResultIntent",
19 protocol: AppIntentProtocol.SnippetIntent,
20 perform: async ({ content }: { content: string }) => {
21 const color = IntentMemoryStorage.get<Color>("color") ?? "systemBlue"
22 return <ResultView content={content} color={color} />
23 }
24})
intent.tsx
1async function runIntent() {
2
3 // 1. 通过 Snippet 请求用户确认颜色
4 await Intent.requestConfirmation(
5 "set",
6 PickColorIntent()
7 )
8
9 // 2. 从 Shortcuts 输入中读取文本
10 const textContent =
11 Intent.shortcutParameter?.type === "text"
12 ? Intent.shortcutParameter.value
13 : "No text parameter from Shortcuts"
14
15 // 3. 创建 SnippetIntent 返回结果
16 const snippetIntentValue = Intent.snippetIntent({
17 snippetIntent: ShowResultIntent({ content: textContent })
18 })
19
20 Script.exit(snippetIntentValue)
21}
22
23runIntent()